package ru.teleology.cubefs.tests;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import org.junit.After;
import org.junit.Before;

import com.sun.org.apache.xml.internal.utils.IntVector;

import ru.teleology.cubefs.api.models.Container;
import ru.teleology.cubefs.api.models.InputStreamAdaptor;
import ru.teleology.cubefs.api.models.LogHandler;
import ru.teleology.cubefs.api.models.OutputStreamAdaptor;
import ru.teleology.cubefs.api.models.StreamManager;
import ru.teleology.cubefs.api.models.TreeMap;
import ru.teleology.cubefs.api.reflection.CoreFactory;
import ru.teleology.cubefs.api.reflection.number.IntNumber;

public class ContainerTestBase {
	private static final String FOLDER = "build"+File.separator+"tests";
	
	protected Container container;
	
	private String testName;
	private String fileName;
	private String lastFileName;
	private String operationName;
	private boolean done = false;
	private int childrenPerNode = -1;
		
	private int containerType = Container.STREAM;

	private int logLevel = LogHandler.ERROR;
	
	private boolean dump = false;
	
	public String getTestName() {
		return testName;
	}
	
	public Container getContainer() {
		return container;
	}

	public void setContainer(Container container) {
		this.container = container;
	}
	
	public void open(String name) {
		try {
			StreamManager manager = (StreamManager) container.GetManager();
			manager.load(new InputStreamAdaptor(new BufferedInputStream(new FileInputStream(getFileName(name)))));
		}
		catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	public String getFileName(String rawName) {
		String name = rawName.replaceAll(" |\\.", "_");
		return FOLDER + File.separator + this.testName + File.separator + fileName+"."+name+".bin";
	}

	protected boolean mkDirs() {
		return new File(FOLDER + File.separator + this.testName).mkdirs(); 
	}
	
	public void dumpBefore(String name) {
		dump(name+"-before");
	}
	
	public void dumpAfter(String name) {
		dump(name+"-after");
	}
	
	public void dump(String name) {
		if (container!=null && isDump()) try {
			StreamManager manager = (StreamManager) container.GetManager();
			mkDirs();
			this.lastFileName = getFileName(name);
			manager.store(new OutputStreamAdaptor(new BufferedOutputStream(new FileOutputStream(lastFileName))));
		}
		catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	public void removeFile(String name) {
		new File(getFileName(name)).delete();
	}

	public String getContainerType() {
		return "Stream";
	}
	
	public void run(Op op) {
		removeFile(operationName + "-before");
	}
	
	public void run(Ops op) {
		done = true;
	}
	
	public class Op {
		public Op(String name) {
			operationName = name;
			dumpBefore(name);
		}
	}
	
	public class Ops {
		public Ops(String name) {
			testName = name;
		}
	}
	
	
	@Before public void createContainer() {
		container = Container.Create(getContainerType(), "0.0.0");

		container.GetManager().GetLogger().SetLogLevel(logLevel);
		
		TreeMap roots = container.roots();
		roots.SetMaxChildrenPerNode(getChildrenPerNode());
	}
	
	@After public void handleOperationException () {
		if (!done) {
			dumpAfter(operationName);
		}
	}

	public int getChildrenPerNode() {
		return childrenPerNode;
	}

	public void setChildrenPerNode(int cildrenPerNode) {
		this.childrenPerNode = cildrenPerNode;
	}

	public int getLogLevel() {
		return logLevel;
	}

	public void setLogLevel(int logLevel) {
		this.logLevel = logLevel;
	}

	public boolean isDump() {
		return dump;
	}

	public void setDump(boolean dump) {
		this.dump = dump;
	}
}
